﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using HeapModel;
using HeapModel.ProgInfo;
using HeapModel.RegionPartition;

namespace MetricExtractor
{
	/// <summary>
	/// Extracts metrics about single reference sets.
	/// 
	/// TotalOffets: Total number of abstract storage locations.
	/// NonNullOffest: Total number of abstract storage locations which are always non null.
	/// NonInterfereOffset: Total number of abstract storage locations where there is never interference ({e | e.interfere == np} in all cases).
	/// OwnerOffset: If the offset always has points to an object that s.t. it is the unique reference to this object.
	/// InterfereImmutableOffset: Total number of abstract storage locations where there is interference but target is immutable ({e | e.interfere == ip \land n.types are immutable}).
	/// InterfereSingletonType: Total number of abstract storage locations where there is interference but target consists only of types that always appear in a single region.
	/// InterfereGlobalSharedType: Total number of abstract storage locations where there is interference but target consists only of types that always appear in a single region.
	/// 
	/// TotalEdges: Total number of edges.
	/// NonNullEdge: Total number of edges which are always non null.
	/// NonInterfereEdge: Total number of edges where there is never interference ({e | e.interfere == np} in all cases).
	/// OwnerEdge: If the edge always has points to an object that s.t. it is the unique reference to this object.
	/// InterfereImmutableEdge: Total number of edges where there is interference but target is immutable ({e | e.interfere == ip \land n.types are immutable}).
	/// InterfereSingletonEdge: Total number of edges where there is interference but target consists only of types that always appear in a single region.
	/// InterfereGlobalSharedEdge: Total number of edges where there is interference but target consists only of types that always appear in a single region.
	/// </summary>
	internal sealed class IndivEdgeMetrics
	{
		public static string[] IndiEdgeMetricsPerEdge = { "TotalEdges", "Internal", "NonNull", "Injective", "Owner", "AliasOnImmutable", "AliasOnSingleton", "AliasOnGlobal", "UnclassifiedAlias" };

		//edge oriented results
		private int m_internalcount = 0;
		private int m_edgecount = 0;
		private int m_nonnullcount = 0;
		private int m_nonintfcount = 0;
		private int m_interferimmutcount = 0;
		private int m_owneredgecount = 0;
		private int m_intfonsingletoncount = 0;
		private int m_intfonglobalrgncount = 0;
		private int m_unclassifiedcount = 0;

		internal IndivEdgeMetrics()
		{
		}

		internal void Extract(RegionGraph hg, Dictionary<string, Tuple<bool, int>> singleregiontype)
		{
			//handle the edge specific extraction
			foreach(RegionNode hr in hg.Regions)
			{
				if(hr.RegionTypes.Count == 1 && hr.RegionTypes.First().IsSpecialNullType)
					continue;

				foreach(RegionEdgeInfo ohrs in hg.FinalSuccMap[hr])
				{
					this.m_edgecount++;

					if(ohrs.Target == hr)
						this.m_internalcount++;

					if(ohrs.IsInjective)
						this.m_nonintfcount++;

					if(ohrs.IsNonNull)
						this.m_nonnullcount++;

					bool isowneroffset = ohrs.IsInjective && hg.FinalPredMap[ohrs.Target].Count((RegionEdgeInfo rei) => rei.Source != null) == 1;
					if(isowneroffset)
						this.m_owneredgecount++;

					if(!ohrs.IsInjective)
					{
						bool isimmutable = ExtractionSupport.AllTypesImmutable(ohrs.Target.RegionTypes);
						if(isimmutable)
							this.m_interferimmutcount++;

						bool issingletonrgntype = ohrs.Target.RegionTypes.All((TypeIdentifier ttid) => singleregiontype[ttid.NameValue].Item1 & singleregiontype[ttid.NameValue].Item2 == 1);
						if(issingletonrgntype)
							this.m_intfonsingletoncount++;

						bool isglobalrgntype = ohrs.Target.RegionTypes.All((TypeIdentifier ttid) => singleregiontype[ttid.NameValue].Item1 & singleregiontype[ttid.NameValue].Item2 != 1);
						if(isglobalrgntype)
							this.m_intfonglobalrgncount++;

						if(!(isimmutable | issingletonrgntype | isglobalrgntype))
							this.m_unclassifiedcount++;
					}
				}
			}
		}

		internal string CSVFormat()
		{ return String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}", this.m_edgecount, this.m_internalcount, this.m_nonnullcount, this.m_nonintfcount, this.m_owneredgecount, this.m_interferimmutcount, this.m_intfonsingletoncount, this.m_intfonglobalrgncount, this.m_unclassifiedcount); }
	}
}
